﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Media;

namespace StarWarsGame
{
    public class NetworkGame : Microsoft.Xna.Framework.Game
    {
        NetworkGamer Player1;
        NetworkGamer Player2;
        // Network stuff
        private readonly NetworkHelper networkHelper;
        private const int maxLocalPlayers = 1;
        private const int maxSessionPlayers = 2;


        struct Bullet
        {
            public Vector3 position;
            public Quaternion rotation;
        }

        private struct VertexPointSprite
        {
            private Vector3 position;
            private float pointSize;

            public VertexPointSprite(Vector3 position, float pointSize)
            {
                this.position = position;
                this.pointSize = pointSize;
            }

            public static readonly VertexElement[] VertexElements =
              {
                  new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
                  new VertexElement(0, sizeof(float)*3, VertexElementFormat.Single, VertexElementMethod.Default, VertexElementUsage.PointSize, 0),
              };
            public static int SizeInBytes = sizeof(float) * (3 + 1);
        }

        enum CollisionType { None, Building, Boundary, Target, WinObject, Player }

        const int maxTargets = 50;
        int[] buildingHeights = new int[] { 0, 2, 2, 6, 5, 4 };

        GraphicsDeviceManager graphics;
        GraphicsDevice device;

        Matrix[] modelTransforms;
        Matrix[] enemyModelTransforms;
        Matrix[] atstModelTransforms;

        Effect effect;
        Vector3 lightDirection = new Vector3(3, -2, 5);
        Matrix viewMatrix;
        Matrix projectionMatrix;

        Texture2D sceneryTexture;
        Texture2D bulletTexture;
        Texture2D[] skyboxTextures;
        Model xwingModel;
        Model targetModel;
        Model skyboxModel;
        Model enemyModel;
        Model ATSTModel;

        Vector3 startXwingPosition = new Vector3(8, 18, -2);
        Vector3 startEnemyPosition = new Vector3(6, 25, 20);
        Vector3 chaseVector = new Vector3();
        Vector3 xwingLastVector = new Vector3();
        Vector3 ATSTposition = new Vector3(8, 15, -8);


        Vector3 xwingPosition = new Vector3(8, 18, -2);
        // Vector3 enemyPosition = new Vector3(13, 5, -3);
        Vector3 enemyPosition = new Vector3(6, 25, 20);
        Quaternion xwingRotation = Quaternion.Identity;
        Quaternion enemyRotation = Quaternion.Identity;
        Quaternion cameraRotation = Quaternion.Identity;
        Quaternion ATSTRotation = Quaternion.Identity;

        // Text
        SpriteBatch spriteBatch;
        SpriteFont spriteFont;

        int[,] floorPlan;
        float gameSpeed = 0.5f;

        VertexBuffer cityVertexBuffer;
        VertexDeclaration texturedVertexDeclaration;
        VertexDeclaration pointSpriteVertexDeclaration;

        BoundingBox[] buildingBoundingBoxes;
        BoundingBox completeCityBox;


        List<BoundingSphere> targetList = new List<BoundingSphere>();
        List<Bullet> bulletList = new List<Bullet>(); double lastBulletTime = 0;

        List<Bullet> enemyBulletList = new List<Bullet>(); double lastEnemyBulletTime = 0;
        List<Bullet> ATSTBulletList = new List<Bullet>(); double lastATSTBulletTime = 0;

        Vector3 newDirVector;

        int nrOfEnemies = 10;


       // List<Enemy> enemyList = new List<Enemy>();

        bool PlayerWins = false;
        bool EnemyWins = false;


        public NetworkGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            networkHelper = new NetworkHelper();
            Services.AddService(typeof(NetworkHelper), networkHelper);
            Services.AddService(typeof(NetworkGame), this);
        }

        /// <summary>
        /// Create a session for a game server
        /// </summary>
        private void CreateSession()
        {
            networkHelper.NetworkGameSession = NetworkSession.Create(
            NetworkSessionType.SystemLink,
            maxLocalPlayers, maxSessionPlayers);
            HookSessionEvents();

        }

        /// <summary>
        /// After creating or joining a network session, we must subscribe to
        /// some events so we will be notified when the session changes state.
        /// </summary>
        void HookSessionEvents()
        {
            networkHelper.NetworkGameSession.GamerJoined +=
            GamerJoinedEventHandler;
            networkHelper.NetworkGameSession.SessionEnded +=
            SessionEndedEventHandler;
        }

        void SessionEndedEventHandler(object sender, NetworkSessionEndedEventArgs e)
        {
           // networkScene.Message = e.EndReason.ToString();
           // networkScene.State = NetworkScene.NetworkGameState.idle;
            CloseSession();
            //if (activeScene != networkScene)
            //{
            //    ShowScene(networkScene);
            //}
        }

        /// <summary>
        /// This event handler will be called whenever a new gamer joins the
        /// session.
        /// </summary>
        void GamerJoinedEventHandler(object sender, GamerJoinedEventArgs e)
        {
            // Associate the ship with the joined player
            if (Player1 == null)
            {
                Player1= e.Gamer;
            }
            else
            {
                Player2 = e.Gamer;
            }
            //if (networkHelper.NetworkGameSession.AllGamers.Count ==
            //maxSessionPlayers)
            //{
            //    actionScene.TwoPlayers = true;
            //    ShowScene(actionScene);
            //}
        }

        /// <summary>
        /// Quit the game session
        /// </summary>
        private void CloseSession()
        {
            networkHelper.NetworkGameSession.Dispose();
            networkHelper.NetworkGameSession = null;
        }

        /// <summary>
        /// Joins an existing network session.
        /// </summary>
        void JoinSession()
        {
            //networkScene.Message = "Joining a game...";
            //networkScene.State = NetworkScene.NetworkGameState.joining;
            try
            {
                // Search for sessions.
                using (AvailableNetworkSessionCollection availableSessions =
                NetworkSession.Find(NetworkSessionType.SystemLink,
                maxLocalPlayers, null))
                {
                    if (availableSessions.Count == 0)
                    {
                       // networkScene.Message = "No network sessions found.";
                        //networkScene.State = NetworkScene.NetworkGameState.idle;
                        return;
                    }
                    // Join the first session we found.
                    networkHelper.NetworkGameSession = NetworkSession.Join(
                    availableSessions[0]);

                    HookSessionEvents();
                }
            }
            catch (Exception e)
            {
                //networkScene.Message = e.Message;
                //networkScene.State = NetworkScene.NetworkGameState.idle;
            }
        }






        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 1200;
            graphics.PreferredBackBufferHeight = 700;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            Window.Title = "Star Wars - Episode M";

            LoadFloorPlan();
            lightDirection.Normalize();
            SetUpBoundingBoxes();
            //  AddTargets();

            LoadEnemies();


            base.Initialize();
        }

        private void LoadEnemies()
        {


            for (int index = 0; index < nrOfEnemies; index++)
            {
                //Vector3 enemyPos = new Vector3(

                //Enemy enemy = new Enemy(
            }
        }

        BasicEffect basicEffect;
        Matrix[] originalTransforms;
        protected override void LoadContent()
        {
            device = graphics.GraphicsDevice;
            basicEffect = new BasicEffect(device, null);

            // Create SpriteBatch and add services
            spriteBatch = new SpriteBatch(device);
            // Font 2D
            spriteFont = Content.Load<SpriteFont>("BerlinSans");

            effect = Content.Load<Effect>("effects");
            sceneryTexture = Content.Load<Texture2D>("texturemap");
            bulletTexture = Content.Load<Texture2D>("bullet");
            xwingModel = LoadModel("xwing");
            enemyModel = Content.Load<Model>("enemyspaceship");
            ATSTModel = Content.Load<Model>("ATST");
            enemyModelTransforms = new Matrix[enemyModel.Bones.Count];
            modelTransforms = new Matrix[xwingModel.Bones.Count];
            atstModelTransforms = new Matrix[ATSTModel.Bones.Count];
            targetModel = LoadModel("target");
            skyboxModel = LoadModel("skybox", out skyboxTextures);
            originalTransforms = new Matrix[ATSTModel.Bones.Count];
            ATSTModel.CopyBoneTransformsTo(originalTransforms);

            ATSTModel.Root.Transform *= Matrix.CreateRotationY(MathHelper.ToRadians(90));

            pointSpritesEffect = Content.Load<Effect>("pointsprites");
            pointSpritesEffect.Parameters["SpriteTexture"].SetValue(
                Content.Load<Texture2D>("fire"));

            // ContentManager contentManager = new ContentManager(this.Services, @"Content\");
            Song mysong = Content.Load<Song>("music");

            MediaPlayer.Play(mysong);



            //vertexPosColDecl = new VertexDeclaration(graphics.GraphicsDevice,
            //    VertexPositionColor.VertexElements); 

            SetUpVertices();
            SetUpCamera();

            pointSpriteVertexDeclaration = new VertexDeclaration(device, VertexPointSprite.VertexElements);
        }

        private Model LoadModel(string assetName)
        {

            Model newModel = Content.Load<Model>(assetName);
            foreach (ModelMesh mesh in newModel.Meshes)
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    meshPart.Effect = effect.Clone(device);
            return newModel;
        }

        private Model LoadModel(string assetName, out Texture2D[] textures)
        {

            Model newModel = Content.Load<Model>(assetName);
            textures = new Texture2D[newModel.Meshes.Count];
            int i = 0;
            foreach (ModelMesh mesh in newModel.Meshes)
                foreach (BasicEffect currentEffect in mesh.Effects)
                    textures[i++] = currentEffect.Texture;

            foreach (ModelMesh mesh in newModel.Meshes)
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    meshPart.Effect = effect.Clone(device);

            return newModel;
        }

        private void LoadFloorPlan()
        {
            floorPlan = new int[,]
             {
                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                 {1,0,0,1,1,0,0,0,1,1,0,0,1,0,1},
                 {1,0,0,1,1,0,0,0,1,0,0,0,1,0,1},
                 {1,0,0,0,1,1,0,1,1,0,0,0,0,0,1},
                 {1,0,0,0,0,0,0,0,0,0,0,1,0,0,1},
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                 //{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                 {1,0,1,1,0,0,0,1,0,0,0,0,0,0,1},
                 {1,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                 {1,0,0,0,0,1,0,0,0,0,0,0,0,0,1},
                 {1,0,0,0,0,1,0,0,0,1,0,0,0,0,1},
                 {1,0,1,0,0,0,0,0,0,1,0,0,0,0,1},
                 {1,0,1,1,0,0,0,0,1,1,0,0,0,1,1},
                 {1,0,0,0,0,0,0,0,1,1,0,0,0,1,1},
                 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
             };

            Random random = new Random();
            int differentBuildings = buildingHeights.Length - 1;
            for (int x = 0; x < floorPlan.GetLength(0); x++)
                for (int y = 0; y < floorPlan.GetLength(1); y++)
                    if (floorPlan[x, y] == 1)
                        floorPlan[x, y] = random.Next(differentBuildings) + 1;
        }

        private void SetUpBoundingBoxes()
        {
            int cityWidth = floorPlan.GetLength(0);
            int cityLength = floorPlan.GetLength(1);


            List<BoundingBox> bbList = new List<BoundingBox>(); for (int x = 0; x < cityWidth; x++)
            {
                for (int z = 0; z < cityLength; z++)
                {
                    int buildingType = floorPlan[x, z];
                    if (buildingType != 0)
                    {
                        int buildingHeight = buildingHeights[buildingType];
                        Vector3[] buildingPoints = new Vector3[2];
                        buildingPoints[0] = new Vector3(x, 0, -z);
                        buildingPoints[1] = new Vector3(x + 1, buildingHeight, -z - 1);
                        if (z < cityLength - 4 && z > 4)
                        {
                            if (x < cityWidth - 4 && x > 4)
                            {
                                ATSTposition = new Vector3(buildingPoints[1].X - 0.5f, buildingPoints[1].Y + 0.8f, buildingPoints[1].Z + 0.5f);
                            }
                        }
                        BoundingBox buildingBox = BoundingBox.CreateFromPoints(buildingPoints);
                        bbList.Add(buildingBox);
                    }
                }
            }
            buildingBoundingBoxes = bbList.ToArray();

            Vector3[] boundaryPoints = new Vector3[2];
            boundaryPoints[0] = new Vector3(0, 0, 0);
            boundaryPoints[1] = new Vector3(cityWidth, 20, -cityLength);
            completeCityBox = BoundingBox.CreateFromPoints(boundaryPoints);
        }

        private void AddTargets()
        {
            int cityWidth = floorPlan.GetLength(0);
            int cityLength = floorPlan.GetLength(1);

            Random random = new Random();

            while (targetList.Count < maxTargets)
            {
                int x = random.Next(cityWidth);
                int z = -random.Next(cityLength);
                float y = (float)random.Next(2000) / 1000f + 1;
                float radius = (float)random.Next(1000) / 1000f * 0.2f + 0.01f;

                BoundingSphere newTarget = new BoundingSphere(new Vector3(x, y, z), radius);

                if (CheckCollision(newTarget) == CollisionType.None)
                    targetList.Add(newTarget);
            }
        }



        private void SetUpCamera()
        {
            viewMatrix = Matrix.CreateLookAt(new Vector3(20, 13, -5), new Vector3(8, 0, -7), new Vector3(0, 1, 0));
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.2f, 500.0f);
        }

        private void SetUpVertices()
        {
            int differentBuildings = buildingHeights.Length - 1;
            float imagesInTexture = 1 + differentBuildings * 2;

            int cityWidth = floorPlan.GetLength(0);
            int cityLength = floorPlan.GetLength(1);


            List<VertexPositionNormalTexture> verticesList = new List<VertexPositionNormalTexture>();
            for (int x = 0; x < cityWidth; x++)
            {
                for (int z = 0; z < cityLength; z++)
                {
                    int currentbuilding = floorPlan[x, z];

                    //floor or ceiling
                    verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2(currentbuilding * 2 / imagesInTexture, 1)));
                    verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                    verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 1)));

                    verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                    verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 0)));
                    verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 1)));

                    if (currentbuilding != 0)
                    {
                        //front wall
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));

                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));

                        //back wall
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));

                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));

                        //left wall
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));

                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));

                        //right wall
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1)));

                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1)));
                        verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0)));
                    }
                }
            }

            cityVertexBuffer = new VertexBuffer(device, verticesList.Count * VertexPositionNormalTexture.SizeInBytes, BufferUsage.WriteOnly);

            cityVertexBuffer.SetData<VertexPositionNormalTexture>(verticesList.ToArray());
            texturedVertexDeclaration = new VertexDeclaration(device, VertexPositionNormalTexture.VertexElements);
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.F2))
            {
                CreateSession();
                 networkHelper.CreateSession();
            }

            networkHelper.Update();
            UpdateCamera(xwingPosition);
            ProcessKeyboard(gameTime);

            if (!PlayerWins && !EnemyWins)
            {
                float moveSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * gameSpeed;
                KeyboardState keys = Keyboard.GetState();
                if (keys.IsKeyDown(Keys.Z))
                {
                    moveSpeed = moveSpeed / 2;
                }

                xwingLastVector = xwingPosition;
                MoveForward(ref xwingPosition, xwingRotation, moveSpeed);
                if (keys.IsKeyDown(Keys.Z))
                {
                    moveSpeed = moveSpeed * 2;
                }

                //UpdateEnemy
                BoundingSphere xwingSpere = new BoundingSphere(xwingPosition, 0.04f);

                if (CheckCollision(xwingSpere) != CollisionType.None)
                {
                    xwingPosition = startXwingPosition;
                    xwingRotation = Quaternion.Identity;
                    //gameSpeed /= 1.1f;
                }

                //BoundingSphere enemySpere = new BoundingSphere(enemyPosition, 0.04f);
                //if (CheckCollision(enemySpere) != CollisionType.None)
                //{
                //    enemyPosition = new Vector3(8, 1, -3);
                //    enemyRotation = Quaternion.Identity;

                //}


                UpdateBulletPositions(moveSpeed);
                UpdateEnemyPosition3(gameTime);
                UpdateATST(gameTime);
                FireATSTBullet(gameTime);
                FireEnemyBullet(gameTime);

                //UpdateATSTBulletsPositions(moveSpeed);


                if (networkHelper.NetworkGameSession != null)
                {
                   // if (gamer.IsLocal)
                   // {
                        // Local gamers always use the main gamepad and keyboard keys
                 //       HandleInput(PlayerIndex.One);
                  //      UpdateShip(gameTime);
                        UpdateNetworkData();
                 //   }
                }

                // Handle the network session
                if (networkHelper.NetworkGameSession != null)
                {
                    // Only send if we are not the server. There is no point sending
                    // packets to ourselves, because we already know what they will
                    // contain!
                    if (!networkHelper.NetworkGameSession.IsHost)
                    {
                        networkHelper.SendClientData();
                    }
                    else
                    {
                        // If we are the server, transmit the game state
                        networkHelper.SendServerData();
                    }
                    // Pump the data
                    networkHelper.NetworkGameSession.Update();
                    // Read any incoming network packets.
                    foreach (LocalNetworkGamer gamer in
                    networkHelper.NetworkGameSession.LocalGamers)
                    {
                        // Keep reading as long as incoming packets are available.
                        while (gamer.IsDataAvailable)
                        {
                            NetworkGamer sender;
                            if (gamer.IsHost)
                            {
                                sender = networkHelper.ReadClientData(gamer);
                                if (!sender.IsLocal)
                                {
                                    HandleClientData();
                                }
                            }
                            else
                            {
                                sender = networkHelper.ReadServerData(gamer);
                                if (!sender.IsLocal)
                                {
                                    HandleServerData();
                                }
                            }
                        }
                    }
                }

                base.Update(gameTime);
            }
        }

        /// <summary>
        /// Update server data with the ship info
        /// </summary>
        private void UpdateNetworkData()
        {
            if (networkHelper.NetworkGameSession.IsHost)
            {
                networkHelper.ServerPacketWriter.Write('S');
                networkHelper.ServerPacketWriter.Write(xwingPosition.ToString());
                //networkHelper.ServerPacketWriter.Write(power);
                //networkHelper.ServerPacketWriter.Write(score);
            }
            else
            {
                networkHelper.ClientPacketWriter.Write('S');
                networkHelper.ClientPacketWriter.Write(xwingPosition.ToString());
                //networkHelper.ClientPacketWriter.Write(power);
                //networkHelper.ClientPacketWriter.Write(score);
            }
        }

        //FireEnemyBullet
        private void FireEnemyBullet(GameTime gameTime)
        {

            double currentTime = gameTime.TotalGameTime.TotalMilliseconds;
            if (currentTime - lastEnemyBulletTime > 500)
            {
                Bullet newBullet = new Bullet();
                newBullet.position = enemyPosition;
                newBullet.rotation = enemyRotation;

                enemyBulletList.Add(newBullet);

                lastEnemyBulletTime = currentTime;
            }

        }
        private void FireATSTBullet(GameTime gameTime)
        {

            double currentTime = gameTime.TotalGameTime.TotalMilliseconds;
            if (currentTime - lastATSTBulletTime > 700)
            {
                Bullet newBullet = new Bullet();
                newBullet.position = ATSTposition;
                newBullet.rotation = ATSTRotation;
                ATSTBulletList.Add(newBullet);

                lastATSTBulletTime = currentTime;
            }

        }

        private void UpdateCamera(Vector3 lookAtPos)
        {

            cameraRotation = Quaternion.Lerp(cameraRotation, xwingRotation, 0.1f);

            Vector3 campos = new Vector3(0, 0.1f, 0.6f);
            campos = Vector3.Transform(campos, Matrix.CreateFromQuaternion(cameraRotation));
            campos += xwingPosition;

            Vector3 camup = new Vector3(0, 1, 0);
            camup = Vector3.Transform(camup, Matrix.CreateFromQuaternion(cameraRotation));

            viewMatrix = Matrix.CreateLookAt(campos, lookAtPos, camup);
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.2f, 500.0f);



            //cameraRotation = Quaternion.Lerp(cameraRotation, enemyRotation, 0.1f);

            //Vector3 campos = new Vector3(0, 0.1f, 0.6f);
            //campos = Vector3.Transform(campos, Matrix.CreateFromQuaternion(cameraRotation));
            //campos += enemyPosition;

            //Vector3 camup = new Vector3(0, 1, 0);
            //camup = Vector3.Transform(camup, Matrix.CreateFromQuaternion(cameraRotation));

            //viewMatrix = Matrix.CreateLookAt(campos, enemyPosition, camup);
            //projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.2f, 500.0f);





        }

        private void ProcessKeyboard(GameTime gameTime)
        {
            float leftRightRot = 0;

            float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
            turningSpeed *= 1.6f * gameSpeed;
            KeyboardState keys = Keyboard.GetState();
            if (keys.IsKeyDown(Keys.Right))
                leftRightRot += turningSpeed;
            if (keys.IsKeyDown(Keys.Left))
                leftRightRot -= turningSpeed;

            float upDownRot = 0;
            if (keys.IsKeyDown(Keys.Down))
                upDownRot += turningSpeed;
            if (keys.IsKeyDown(Keys.Up))
                upDownRot -= turningSpeed;

            Quaternion additionalRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), leftRightRot) * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), upDownRot);
            xwingRotation *= additionalRot;

            if (keys.IsKeyDown(Keys.Space))
            {
                double currentTime = gameTime.TotalGameTime.TotalMilliseconds;
                if (currentTime - lastBulletTime > 100)
                {
                    Bullet newBullet = new Bullet();
                    newBullet.position = xwingPosition;
                    newBullet.rotation = xwingRotation;
                    bulletList.Add(newBullet);

                    lastBulletTime = currentTime;
                }
            }
            if (keys.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }
            if (keys.IsKeyDown(Keys.R))
            {
                Restart();
            }

            if (keys.IsKeyDown(Keys.B))
            {
                UpdateCamera(enemyPosition);

            }

            if (networkHelper.NetworkGameSession != null)
            {
                // If we are the server, send using the server packets
                if (networkHelper.NetworkGameSession.IsHost)
                {
                    networkHelper.ServerPacketWriter.Write('P');
                    //networkHelper.ServerPacketWriter.Write(
                    //actionScene.Paused);
                }
                else
                {
                    networkHelper.ClientPacketWriter.Write('P');
                  //  networkHelper.ClientPacketWriter.Write(

                   // actionScene.Paused);
                }
            }
        }

        /// <summary>
        /// Handle all data incoming from the client
        /// </summary>
        public void HandleClientData()
        {
            while (networkHelper.ClientPacketReader.PeekChar() != -1)
            {
                char header = networkHelper.ClientPacketReader.ReadChar();
                switch (header)
                {
                    case 'P':
                       // Paused = networkHelper.ClientPacketReader.ReadBoolean();
                        break;
                }
            }
        }

        /// <summary>
        /// Handle all data incoming from the server
        /// </summary>
        public void HandleServerData()
        {
            while (networkHelper.ServerPacketReader.PeekChar() != -1)
            {
                char header = networkHelper.ServerPacketReader.ReadChar();
                switch (header)
                {
                    case 'P':
                      //  Paused = networkHelper.ServerPacketReader.ReadBoolean();
                        break;
                }
            }
        }


        

        private void Restart()
        {
            explosionPlays = false;
            enemyBulletList.Clear();
            ATSTBulletList.Clear();
            bulletList.Clear();
            PlayerWins = false;
            EnemyWins = false;
            //randomize ship positions
            Random random = new Random();
            float randomNumberX1 = (float)random.Next(1, 15);
            float randomNumberX2 = (float)random.Next(1, 15);

            float randomNumberY1 = (float)random.Next(8, 15);
            float randomNumberY2 = (float)random.Next(1, 15);

            float randomNumberZ1 = (float)random.Next(-15, -1);
            float randomNumberZ2 = (float)random.Next(1, 15);

            startXwingPosition = new Vector3(randomNumberX1, randomNumberY1, randomNumberZ1);
            startEnemyPosition = new Vector3(randomNumberX2, randomNumberY2, randomNumberZ2);

            xwingPosition = startXwingPosition;
            xwingRotation = Quaternion.Identity;
            gameSpeed /= 1.0f;

            enemyPosition = startEnemyPosition;
            enemyRotation = Quaternion.Identity;

        }
        //chaseVector

        private void MoveEnemyForward(ref Vector3 position, Quaternion rotationQuat, float speed, Vector3 chaseVector)
        {
            //Vector3 addVector = Vector3.Transform(chaseVector, rotationQuat);
            Vector3 addVector = Vector3.Transform(chaseVector, rotationQuat);
            position += addVector * speed;
        }

        private void MoveForward(ref Vector3 position, Quaternion rotationQuat, float speed)
        {
            Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat);
            position += addVector * speed;
        }

        private void MoveATSTForward(ref Vector3 position, Vector3 lookAtPos, Quaternion rotationQuat, float speed)
        {
            Vector3 addVector = new Vector3();

            //if (lookAtPos.Z < position.Z)
            //{
            //    addVector = Vector3.Transform(new Vector3(0, 0, 1), rotationQuat);
            //}
            //if (lookAtPos.Z > position.Z)
            //{
            addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat);
            //}

            addVector.Y = 0;

            position += addVector * speed;
        }

        private CollisionType CheckCollision(BoundingSphere sphere)
        {


            for (int i = 0; i < buildingBoundingBoxes.Length; i++)
                if (buildingBoundingBoxes[i].Contains(sphere) != ContainmentType.Disjoint)
                    return CollisionType.Building;

            if (completeCityBox.Contains(sphere) != ContainmentType.Contains)
                return CollisionType.Boundary;

            for (int i = 0; i < targetList.Count; i++)
            {
                if (targetList[i].Contains(sphere) != ContainmentType.Disjoint)
                {
                    targetList.RemoveAt(i);
                    i--;
                    AddTargets();

                    return CollisionType.Target;
                }
            }


            return CollisionType.None;
        }

        private CollisionType CheckIfHit(BoundingSphere sphere)
        {
            BoundingSphere ATSTSpere = new BoundingSphere(ATSTposition, 0.40f);
            BoundingSphere enemySpere = new BoundingSphere(enemyPosition, 0.04f);
            BoundingSphere playerSpere = new BoundingSphere(xwingPosition, 0.04f);

            if (playerSpere.Contains(sphere) != ContainmentType.Disjoint)
                return CollisionType.Player;

            if (ATSTSpere.Contains(sphere) != ContainmentType.Disjoint)
                return CollisionType.WinObject;

            return CollisionType.None;
        }

        private void UpdateEnemyPosition2(GameTime gameTime)
        {
            //see in what direction 
            Vector3 playerMove = xwingPosition - chaseVector;
            Vector3 enemyMove = enemyPosition - xwingLastVector;

            Vector3 changeVector = playerMove - enemyMove;
            Vector3 distVector = xwingPosition - enemyPosition;


            float speedFactor = Math.Abs(distVector.Z);

            //float enemyMoveSpeed = 0.3f;
            float enemyMoveSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * (gameSpeed);// * 1.0f);

            bool chaseXwing = true;
            if (chaseXwing)
            {
                float leftRightRot = 0;

                float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
                float turningFactorX = Math.Abs(distVector.X);



                float turningFactorY = 1.0f;
                float testupDownRot = 0;
                if (distVector.Y > 0 || distVector.Y > 0)
                    testupDownRot += turningSpeed * turningFactorY;
                if (distVector.Y < 0 || distVector.Y < 0)
                    testupDownRot -= turningSpeed * turningFactorY;
                Quaternion testNextYRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), 0) * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), testupDownRot);
                Vector3 testMoveVector = Vector3.Transform(new Vector3(0, 0, -1), testNextYRot);
                if (testMoveVector.Y < xwingPosition.Y)
                {
                    turningFactorY -= Math.Abs(distVector.Y) / 10;
                }
                if (testMoveVector.Y > xwingPosition.Y)
                {
                    turningFactorY += Math.Abs(distVector.Y) / 10;
                }

                turningSpeed *= 1.0f * gameSpeed * 1.2f;
                float upDownRot = 0;
                if (distVector.X > 0)//keys.IsKeyDown(Keys.Right))
                    leftRightRot += turningSpeed;
                if (distVector.X < 0)
                    leftRightRot -= turningSpeed;


                if (distVector.Y > 0.05)
                {

                    //if(enemyRotation.X == 0)
                    //{
                    upDownRot += turningSpeed * turningFactorY;
                    //}
                }
                if (distVector.Y < -0.05)
                {

                    //if (enemyRotation.X == 0)// || Math.Abs(enemyRotation.X) < 0.29)
                    //{
                    upDownRot -= turningSpeed * turningFactorY;
                    //}
                }
                //if (distVector.Y < -0.5 && enemyRotation.X < -0.3)
                //    upDownRot -= turningSpeed;

                Quaternion additionalRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), leftRightRot) * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), upDownRot);
                if (Math.Abs(enemyRotation.X) < Math.Abs(lastRotXValue))
                {
                    enemyRotation *= additionalRot;
                    lastRotXValue = distVector.Y / 2;
                }
                else
                {
                    lastRotXValue = distVector.Y;
                    //enemyRotation.X = 0.0f;
                }
            }

            //  Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat);
            chaseVector = xwingPosition;//; - chaseVector; //x.Transformation.Translate - Transformation.Translate;
            xwingLastVector = enemyPosition;
            //  float distanceToPlayer = chaseVector.Length();
            // Normalize chase vector
            //
            //  chaseVector *= (1.0f / distanceToPlayer);
            //MoveEnemyForward(ref enemyPosition, enemyRotation, enemyMoveSpeed, chaseVector);




            MoveForward(ref enemyPosition, enemyRotation, enemyMoveSpeed);


            //see if player is in view for enemy



        }

        public static float GetAngleBetweenVectors(Vector3 vec1, Vector3 vec2)
        {
            // See http://en.wikipedia.org/wiki/Vector_(spatial)
            // for help and check out the Dot Product section ^^
            // Both vectors are normalized so we can save deviding through the
            // lengths.
            return (float)Math.Acos(Vector3.Dot(vec1, vec2));
        }

        public float GetAngleBetweenVectors(Vector3 vec1, Vector3 vec2, Vector3 oldPos)
        {
            // See http://en.wikipedia.org/wiki/Vector_(spatial)
            // for help and check out the Dot Product section ^^
            // Both vectors are normalized so we can save deviding through the
            // lengths.

            //if (distVector.Z < 0)
            //{

            //    return (float)Math.Asin(v);
            float lowerVal = (float)(Math.Sqrt(Math.Pow(vec1.X, 2) + Math.Pow(vec1.Y, 2) + Math.Pow(vec1.Z, 2)) * Math.Sqrt(Math.Pow(vec2.X, 2) + Math.Pow(vec2.Y, 2) + Math.Pow(vec2.Z, 2)));
            double cos2 = (double)Vector3.Dot(vec1, vec2) / lowerVal;

            double cos = (double)(vec1.X * vec2.X + vec1.Y * vec2.Y + vec1.Z * vec2.Z) / lowerVal;



            return (float)Math.Acos(cos) * 180 / MathHelper.Pi;

            Vector3.Normalize(vec1);
            Vector3.Normalize(vec2);
            //  return (float) Math.Acos(Vector3.Dot(vec1, vec2));

            //if (xwingPosition.Y > enemyPosition.Y)
            //{
            //    float bSide = xwingPosition.Z - enemyPosition.Z;
            //    float aSide = xwingPosition.Y - enemyPosition.Y;

            //    float coss = (float)Math.Acos(Math.Cos(bSide / aSide));

            //    return coss * 180 / MathHelper.Pi;
            //}
            //else
            //{
            //    float bSide = xwingPosition.Z - enemyPosition.Z;
            //    float aSide = enemyPosition.Y - xwingPosition.Y;

            //    float coss = (float)Math.Acos(Math.Cos(bSide / aSide));

            //    return -coss * 180 / MathHelper.Pi;

            //}
            //return (float)Math.Acos(coss) * 180 / MathHelper.Pi;


            //}
            //else
            //{
            //    return (float)Math.Acos(Vector3.Dot(vec1, vec2));
            //}

            //return Math.Acos(Vector2.Dot(VectorA, VectorB) / (VectorA.Length() * VectorB.Length())) * 180 / MathHelper.Pi; 


            float kValue = (vec2.Y - chaseVector.Y) / (vec2.Z - chaseVector.Z);


            //u(t) = Kp*e(t) + Ki * Integral(e(t)dt) + Kp de(t)/dt  

            //Manual tuning
            //If the system must remain online, one tuning method is to first set Ki and Kd values to zero.
            //Increase the Kp until the output of the loop oscillates,
            //then the Kp should be left set to be approximately
            //half of that value for a "quarter amplitude decay" type response.
            //Then increase Ki until any offset is correct in sufficient time for the process.
            //However, too much Ki will cause instability. Finally, increase Kd, if required,
            //until the loop is acceptably quick to reach its reference after a load disturbance.
            //However, too much Kd will cause excessive response and overshoot.
            //A fast PID loop tuning usually overshoots slightly to reach the setpoint more quickly;
            //however, some systems cannot accept overshoot, in which case an "over-damped" closed-loop system
            //is required, which will require a Kp setting significantly less than half that of the Kp setting
            //causing oscillation.





        }

        //Ex. y = k*x + m
        private float IntegrateFormula(float k, float x, float m, int startInterval, int endInterval)
        {
            float integratedValue = 0.0f;
            integratedValue = endInterval * x - startInterval * x;
            return integratedValue;
        }



        Vector3 distVector;

        private void UpdateATST(GameTime gameTime)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;


            //ATSTposition
            Vector3 directionVector = Vector3.Normalize(xwingPosition - ATSTposition);

            Vector3 newUp = Math.Abs(Vector3.Dot(directionVector, Vector3.Up)) != 1
                                ? Vector3.Up
                                : Vector3.Cross(Vector3.Forward, directionVector);

            Matrix lookAt = Matrix.CreateWorld(ATSTposition, directionVector, newUp);

            ATSTRotation = Quaternion.CreateFromRotationMatrix(lookAt);


            //float enemyMoveSpeed = 2.0f;
            Quaternion additionalRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), MathHelper.Pi / 2) * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), MathHelper.Pi / 2);
            //ATSTRotation *= additionalRot;
            // ATSTRotation = Quaternion.Identity;

            float enemyMoveSpeed = (gameTime.ElapsedGameTime.Milliseconds / 500.0f * (gameSpeed)) * 0.02f;
            // MoveForward(ref ATSTposition, ATSTRotation, enemyMoveSpeed);

            //    Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat);
            //GetAngleBetweenVectors
            // ATSTModel.Root.Transform *= Matrix.CreateRotationY(GetAngleBetweenVectors(ATSTposition, xwingPosition));
            Vector3 aimPosition = xwingPosition + xwingPosition - xwingLastVector;

            MoveATSTForward(ref ATSTposition, aimPosition, ATSTRotation, enemyMoveSpeed);
        }


        private void UpdateEnemyPosition3(GameTime gameTime)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            distVector = xwingPosition - enemyPosition;

            // This code causes the tank to change its speed gradually while it 
            // moves toward the waypoint previousMoveSpeed tracks how fast the 
            // tank was going, desiredMoveSpeed finds how fast the tank want to 
            // go and Math.Clamp keeps the tank from accelerating or decelerating 
            // too fast.
            //float previousMoveSpeed = tank.MoveSpeed;
            //float desiredMoveSpeed = FindMaxMoveSpeed(tank.Waypoints.Peek());
            //tank.MoveSpeed = MathHelper.Clamp(desiredMoveSpeed,
            //    previousMoveSpeed - Tank.MaxMoveSpeedDelta * elapsedTime,
            //    previousMoveSpeed + Tank.MaxMoveSpeedDelta * elapsedTime);

            // This code causes the tank to turn towards the waypoint.  First we 
            // take the vector that represents the tanks’ current heading, 
            // Tank.Direction, and convert it into an angle in radians. Then we 
            // use TurnToFace to make the tank turn towards it’s waypoint based 
            // on it’s turning speed, Tank,MaxAngualrVelocity. After we have the 
            // new direction in radian we convert it back into a vector.
            //float facingDirection = (float)Math.Atan2();
            //    //.Y, tank.Direction.X);
            //facingDirection = TurnToFace(tank.Location, tank.Waypoints.Peek(),
            //        facingDirection, Tank.MaxAngularVelocity * elapsedTime);
            //tank.Direction = new Vector2(
            //    (float)Math.Cos(facingDirection),
            //    (float)Math.Sin(facingDirection));

            // Quaternion targetRotation = Quaternion.CreateFromRotationMatrix.LookRotation(pos - transform.position, Vector3.up);
            //targetRotation.x = 0;
            //targetRotation.z = 0;
            enemyRotation = Quaternion.Slerp(enemyRotation, xwingRotation, .5f);

            Vector3 directionVector = Vector3.Normalize(xwingPosition - enemyPosition);

            Vector3 newUp = Math.Abs(Vector3.Dot(directionVector, Vector3.Up)) != 1
                                ? Vector3.Up
                                : Vector3.Cross(Vector3.Forward, directionVector);

            Matrix lookAt = Matrix.CreateWorld(enemyPosition, directionVector, newUp);

            enemyRotation = Quaternion.CreateFromRotationMatrix(lookAt);


            //moveDirection = transform.TransformDirection(0, 0, speed);
            //rigidbody.MovePosition(rigidbody.position + moveDirection); 
            float enemyMoveSpeed = (gameTime.ElapsedGameTime.Milliseconds / 500.0f * (gameSpeed)) * 1.2f;
            MoveForward(ref enemyPosition, enemyRotation, enemyMoveSpeed);


        }

        private void UpdateEnemyPosition(GameTime gameTime)
        {

            //see in what direction 
            Vector3 playerMove = xwingPosition - chaseVector;
            Vector3 enemyMove = enemyPosition - xwingLastVector;

            Vector3 changeVector = playerMove - enemyMove;
            distVector = xwingPosition - enemyPosition;

            angle = GetAngleBetweenVectors(enemyPosition, xwingPosition, chaseVector);


            float enemyMoveSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * (gameSpeed);// * 1.0f);

            bool chaseXwing = true;
            if (chaseXwing)
            {
                float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;

                turningSpeed *= 1.6f * gameSpeed;

                float leftRightRot = 0;
                upDownRot = 0;

                //if (enemyRotation.X > angle)
                //    leftRightRot += turningSpeed;
                //if (enemyRotation.X < angle)
                //    leftRightRot -= turningSpeed;
                //  upDownRot = angle;

                // if (enemyRotation.Y > angle)                  
                //     upDownRot += turningSpeed;

                //if (enemyRotation.Y < angle)
                //    upDownRot -= turningSpeed;

                Quaternion additionalRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), leftRightRot) * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), upDownRot);

                enemyRotation *= additionalRot;

            }


            chaseVector = xwingPosition;
            xwingLastVector = enemyPosition;

            MoveForward(ref enemyPosition, enemyRotation, enemyMoveSpeed);

        }

        public float ToAxisAngle(Quaternion q, Vector3 axis, float angle)
        {
            angle = (float)Math.Acos(q.W);
            float ooScale = 1.0f / (float)Math.Sin(angle);
            angle *= 2.0f;

            axis = new Vector3(-q.X * ooScale, -q.Y * ooScale, -q.Z * ooScale);
            return angle;
        }

        private float lastRotXValue = 0.3f;




        private void UpdateBulletPositions(float moveSpeed)
        {
            for (int i = 0; i < bulletList.Count; i++)
            {
                Bullet currentBullet = bulletList[i];
                MoveForward(ref currentBullet.position, currentBullet.rotation, moveSpeed * 5.0f);
                bulletList[i] = currentBullet;

                BoundingSphere bulletSphere = new BoundingSphere(currentBullet.position, 0.05f);
                CollisionType colType = CheckCollision(bulletSphere);
                if (colType != CollisionType.None)
                {
                    bulletList.RemoveAt(i);
                    i--;

                    if (colType == CollisionType.Target)
                        gameSpeed *= 1.05f;

                }

                CollisionType bulletHitType = CheckIfHit(bulletSphere);
                if (bulletHitType == CollisionType.WinObject)
                    PlayerWins = true;
            }

            for (int i = 0; i < enemyBulletList.Count; i++)
            {
                Bullet currentBullet = enemyBulletList[i];
                MoveForward(ref currentBullet.position, currentBullet.rotation, moveSpeed * 7.0f);
                enemyBulletList[i] = currentBullet;

                BoundingSphere bulletSphere = new BoundingSphere(currentBullet.position, 0.05f);
                CollisionType colType = CheckCollision(bulletSphere);
                if (colType != CollisionType.None && colType != CollisionType.Boundary)
                {
                    enemyBulletList.RemoveAt(i);
                    i--;

                    if (colType == CollisionType.Target)
                        gameSpeed *= 1.05f;

                }

                CollisionType bulletHitType = CheckIfHit(bulletSphere);
                if (bulletHitType == CollisionType.Player)
                    EnemyWins = true;
            }

            for (int i = 0; i < ATSTBulletList.Count; i++)
            {
                Bullet currentBullet = ATSTBulletList[i];
                MoveForward(ref currentBullet.position, currentBullet.rotation, moveSpeed * 3.0f);
                ATSTBulletList[i] = currentBullet;

                BoundingSphere bulletSphere = new BoundingSphere(currentBullet.position, 0.05f);
                CollisionType colType = CheckCollision(bulletSphere);
                if (colType != CollisionType.None && colType != CollisionType.Boundary)
                {
                    ATSTBulletList.RemoveAt(i);
                    i--;

                    if (colType == CollisionType.Target)
                        gameSpeed *= 1.05f;

                }

                CollisionType bulletHitType = CheckIfHit(bulletSphere);
                if (bulletHitType == CollisionType.Player)
                    EnemyWins = true;
            }

        }

        protected override void Draw(GameTime gameTime)
        {
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkSlateBlue, 1.0f, 0);

            DrawSkybox();
            DrawCity();
            DrawModel(gameTime);
            DrawEnemy2(gameTime);
            DrawTargets();

            DrawBullets3();
            DrawATSTBullets();
            DrawEnemyBullets();

            DrawATST(gameTime);


            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);

            spriteBatch.DrawString(spriteFont, "Mission: Destroy the ATST before you get hited!", new Vector2(10, 5), Color.Blue);
            spriteBatch.DrawString(spriteFont, "Use the arrows to navigate and space to fire. Z slows down the xwings speed.", new Vector2(10, 25), Color.Blue);
            spriteBatch.DrawString(spriteFont, "Use B to look behind the xwing.", new Vector2(10, 45), Color.Blue);

            if (PlayerWins)
            {
                spriteBatch.DrawString(spriteFont, "You win! Press R to restart or Esc to exit.", new Vector2(300, 275), Color.Green);
                if (!explosionPlays)
                {
                    SoundEffect soundEffect = Content.Load<SoundEffect>("explosion");
                    soundEffect.Play();
                    explosionPlays = true;
                }
            }
            if (EnemyWins)
            {
                spriteBatch.DrawString(spriteFont, "You lose! Press R to restart or Esc to exit.", new Vector2(300, 275), Color.Red);
                if (!explosionPlays)
                {
                    SoundEffect soundEffect = Content.Load<SoundEffect>("explosion");
                    soundEffect.Play();
                    explosionPlays = true;
                }
            }

            spriteBatch.DrawString(spriteFont, "XwingPos: " + xwingPosition.ToString(), new Vector2(130, 105), Color.Aqua);

            spriteBatch.DrawString(spriteFont, "EnemyPos: " + enemyPosition.ToString(), new Vector2(130, 125), Color.Aqua);

            spriteBatch.DrawString(spriteFont, "XwingRotation: " + xwingRotation.ToString(), new Vector2(130, 145), Color.Aqua);

            spriteBatch.DrawString(spriteFont, "enemyRotation: " + enemyRotation.ToString(), new Vector2(130, 165), Color.Purple);

            //spriteBatch.DrawString(spriteFont, "angle: " + angle.ToString(), new Vector2(10, 45), Color.Aqua);

            //spriteBatch.DrawString(spriteFont, "enemyRotation: " + enemyRotation.ToString(), new Vector2(10, 65), Color.Purple);

            //spriteBatch.DrawString(spriteFont, "Distance: " + distVector.ToString(), new Vector2(10, 85), Color.Aqua);


            spriteBatch.End();

            base.Draw(gameTime);
        }

        bool explosionPlays = false;

        float upDownRot;
        float angle;

        private void DrawCity()
        {
            effect.CurrentTechnique = effect.Techniques["Textured"];
            effect.Parameters["xWorld"].SetValue(Matrix.Identity);
            effect.Parameters["xView"].SetValue(viewMatrix);
            effect.Parameters["xProjection"].SetValue(projectionMatrix);
            effect.Parameters["xTexture"].SetValue(sceneryTexture);
            effect.Parameters["xEnableLighting"].SetValue(true);
            effect.Parameters["xLightDirection"].SetValue(lightDirection);
            effect.Parameters["xAmbient"].SetValue(0.5f);
            effect.Begin();
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Begin();
                device.VertexDeclaration = texturedVertexDeclaration;
                device.Vertices[0].SetSource(cityVertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes);
                device.DrawPrimitives(PrimitiveType.TriangleList, 0, cityVertexBuffer.SizeInBytes / VertexPositionNormalTexture.SizeInBytes / 3);
                pass.End();
            }
            effect.End();
        }

        private void DrawModel(GameTime gameTime)
        {
            Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(xwingRotation) * Matrix.CreateTranslation(xwingPosition);
            //float time = (float)gameTime.TotalRealTime.TotalMilliseconds / 1000.0f;
            //Matrix worldMatrix = Matrix.CreateScale(0.005f) * Matrix.CreateTranslation(7.0f, 0, 0) * Matrix.CreateRotationY(-time);
            Matrix[] xwingTransforms = new Matrix[xwingModel.Bones.Count];
            xwingModel.CopyAbsoluteBoneTransformsTo(xwingTransforms);

            xwingModel.CopyAbsoluteBoneTransformsTo(modelTransforms);
            foreach (ModelMesh mesh in xwingModel.Meshes)
            {
                // foreach (Effect currentEffect in mesh.Effects)
                for (int index = 0; index < mesh.Effects.Count; index++)
                {
                    Effect currentEffect = mesh.Effects[index] as Effect;
                    if (currentEffect != null)
                    {
                        currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"];
                        currentEffect.Parameters["xWorld"].SetValue(xwingTransforms[mesh.ParentBone.Index] * worldMatrix);
                        currentEffect.Parameters["xView"].SetValue(viewMatrix);
                        currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);
                        currentEffect.Parameters["xEnableLighting"].SetValue(true);
                        currentEffect.Parameters["xLightDirection"].SetValue(lightDirection);
                        currentEffect.Parameters["xAmbient"].SetValue(0.5f);
                    }
                }
                mesh.Draw();
            }

            //foreach (ModelMesh mesh in xwingModel.Meshes)
            //{                
            //    //foreach (BasicEffect effect in mesh.Effects)
            //    for (int index = 0; index < mesh.Effects.Count; index++)
            //    {
            //        BasicEffect currentEffect = mesh.Effects[index] as BasicEffect;
            //        if (currentEffect != null)
            //        {
            //            currentEffect.EnableDefaultLighting();
            //            currentEffect.World = modelTransforms[mesh.ParentBone.Index] * worldMatrix;
            //            currentEffect.View = viewMatrix;// fpsCam.ViewMatrix;
            //            currentEffect.Projection = projectionMatrix;// fpsCam.ProjectionMatrix;
            //        }
            //    }
            //    mesh.Draw();
            //}
        }

        private void DrawATST(GameTime gameTime)
        {
            //Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(xwingRotation) * Matrix.CreateTranslation(new Vector3(xwingPosition.X, xwingPosition.Y, xwingPosition.Z - 0.4f));//xwingPos.2,2,-5));
            ////float time = (float)gameTime.TotalRealTime.TotalMilliseconds / 1000.0f;
            ////Matrix worldMatrix = Matrix.CreateScale(0.005f) * Matrix.CreateTranslation(7.0f, 0, 0) * Matrix.CreateRotationY(-time);
            //Matrix[] atstTransforms = new Matrix[ATSTModel.Bones.Count];
            //ATSTModel.CopyAbsoluteBoneTransformsTo(atstTransforms);

            //ATSTModel.CopyAbsoluteBoneTransformsTo(atstModelTransforms);

            //foreach (ModelMesh mesh in ATSTModel.Meshes)
            //{
            //    // foreach (Effect currentEffect in mesh.Effects)
            //    for (int index = 0; index < mesh.Effects.Count; index++)
            //    {
            //        Effect currentEffect = mesh.Effects[index] as Effect;
            //        if (currentEffect != null)
            //        {
            //            currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"];
            //            currentEffect.Parameters["xWorld"].SetValue(atstTransforms[mesh.ParentBone.Index] * worldMatrix);
            //            currentEffect.Parameters["xView"].SetValue(viewMatrix);
            //            currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);
            //            currentEffect.Parameters["xEnableLighting"].SetValue(true);
            //            currentEffect.Parameters["xLightDirection"].SetValue(lightDirection);
            //            currentEffect.Parameters["xAmbient"].SetValue(0.5f);
            //        }
            //    }
            //    mesh.Draw();
            //}    

            //Matrix[] originalTransforms = new Matrix[ATSTModel.Bones.Count];
            //draw model
            ////////Matrix newCanonMat = Matrix.CreateRotationX(0) * originalTransforms[10];
            ////////ATSTModel.Bones[10].Transform = newCanonMat;

            ////////Matrix newTurretMat = Matrix.CreateRotationY(0) * originalTransforms[9];
            ////////ATSTModel.Bones[9].Transform = newTurretMat;

            ////   Matrix worldMatrix = Matrix.CreateScale(xwingPosition.X, xwingPosition.Y, xwingPosition.Z + 0.4f);
            ATSTModel.CopyAbsoluteBoneTransformsTo(atstModelTransforms);

            Matrix worldMatrix = Matrix.CreateScale(0.0020f, 0.0020f, 0.0020f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(ATSTRotation) * Matrix.CreateTranslation(ATSTposition);//xwingPos.2,2,-5));


            foreach (ModelMesh mesh in ATSTModel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = atstModelTransforms[mesh.ParentBone.Index] * worldMatrix;
                    effect.View = viewMatrix;
                    effect.Projection = projectionMatrix;
                }
                mesh.Draw();
            }

            base.Draw(gameTime);
        }

        private void DrawEnemy2(GameTime gameTime)
        {

            enemyModel.CopyAbsoluteBoneTransformsTo(enemyModelTransforms);

            Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(enemyRotation) * Matrix.CreateTranslation(enemyPosition);


            foreach (ModelMesh mesh in enemyModel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = enemyModelTransforms[mesh.ParentBone.Index] * worldMatrix;
                    effect.View = viewMatrix;
                    effect.Projection = projectionMatrix;
                }
                mesh.Draw();
            }

            base.Draw(gameTime);
        }


        private void DrawEnemy(GameTime gameTime)
        {
            Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(enemyRotation) * Matrix.CreateTranslation(enemyPosition);
            //Matrix worldMatrix = Matrix.CreateScale(targetList[i].Radius) * Matrix.CreateTranslation(targetList[i].Center);
            //float time = (float)gameTime.TotalRealTime.TotalMilliseconds / 1000.0f;
            //Matrix worldMatrix = Matrix.CreateScale(0.005f) * Matrix.CreateTranslation(7.0f, 0, 0) * Matrix.CreateRotationY(-time);
            Matrix[] enemyTransforms = new Matrix[enemyModel.Bones.Count];
            enemyModel.CopyAbsoluteBoneTransformsTo(enemyTransforms);

            enemyModel.CopyAbsoluteBoneTransformsTo(enemyModelTransforms);
            foreach (ModelMesh mesh in enemyModel.Meshes)
            {
                // foreach (Effect currentEffect in mesh.Effects)
                for (int index = 0; index < mesh.Effects.Count; index++)
                {
                    Effect currentEffect = mesh.Effects[index] as Effect;
                    if (currentEffect != null)
                    {
                        currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"];
                        currentEffect.Parameters["xWorld"].SetValue(enemyTransforms[mesh.ParentBone.Index] * worldMatrix);
                        currentEffect.Parameters["xView"].SetValue(viewMatrix);
                        currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);
                        currentEffect.Parameters["xEnableLighting"].SetValue(true);
                        currentEffect.Parameters["xLightDirection"].SetValue(lightDirection);
                        currentEffect.Parameters["xAmbient"].SetValue(0.5f);
                    }
                }
                mesh.Draw();
            }
            //foreach (ModelMesh mesh in enemyModel.Meshes)
            //{
            //    //foreach (BasicEffect effect in mesh.Effects)
            //    for (int index = 0; index < mesh.Effects.Count; index++)
            //    {
            //        BasicEffect currentEffect = mesh.Effects[index] as BasicEffect;
            //        if (currentEffect != null)
            //        {
            //            currentEffect.EnableDefaultLighting();
            //            currentEffect.World = enemyModelTransforms[mesh.ParentBone.Index] * worldMatrix;
            //            currentEffect.View = viewMatrix;// fpsCam.ViewMatrix;
            //            currentEffect.Projection = projectionMatrix;// fpsCam.ProjectionMatrix;
            //        }
            //    }
            //    mesh.Draw();
            //}
        }

        private void DrawTargets()
        {
            for (int i = 0; i < targetList.Count; i++)
            {
                Matrix worldMatrix = Matrix.CreateScale(targetList[i].Radius) * Matrix.CreateTranslation(targetList[i].Center);

                Matrix[] targetTransforms = new Matrix[targetModel.Bones.Count];
                targetModel.CopyAbsoluteBoneTransformsTo(targetTransforms);
                foreach (ModelMesh mesh in targetModel.Meshes)
                {
                    foreach (Effect currentEffect in mesh.Effects)
                    {
                        currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"];
                        currentEffect.Parameters["xWorld"].SetValue(targetTransforms[mesh.ParentBone.Index] * worldMatrix);
                        currentEffect.Parameters["xView"].SetValue(viewMatrix);
                        currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);
                        currentEffect.Parameters["xEnableLighting"].SetValue(true);
                        currentEffect.Parameters["xLightDirection"].SetValue(lightDirection);
                        currentEffect.Parameters["xAmbient"].SetValue(0.5f);
                    }
                    mesh.Draw();
                }
            }
        }

        private void DrawBullets()
        {
            if (bulletList.Count > 0)
            {
                VertexPointSprite[] spriteArray = new VertexPointSprite[bulletList.Count];
                for (int i = 0; i < bulletList.Count; i++)
                    spriteArray[i] = new VertexPointSprite(bulletList[i].position, 50);

                effect.CurrentTechnique = effect.Techniques["PointSprites"];
                Matrix worldMatrix = Matrix.Identity;
                effect.Parameters["xWorld"].SetValue(worldMatrix);
                effect.Parameters["xView"].SetValue(viewMatrix);
                effect.Parameters["xProjection"].SetValue(projectionMatrix);
                effect.Parameters["xTexture"].SetValue(bulletTexture);

                device.RenderState.PointSpriteEnable = true;
                device.RenderState.AlphaBlendEnable = true;
                device.RenderState.SourceBlend = Blend.One;
                device.RenderState.DestinationBlend = Blend.One;

                effect.Begin();
                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    device.VertexDeclaration = pointSpriteVertexDeclaration;
                    device.DrawUserPrimitives(PrimitiveType.PointList, spriteArray, 0, spriteArray.Length);
                    pass.End();
                }
                effect.End();

                device.RenderState.PointSpriteEnable = false;
                device.RenderState.AlphaBlendEnable = false;
            }
        }

        private void DrawBullets2()
        {
            if (bulletList.Count > 0)
            {
                VertexPointSprite[] spriteArray = new VertexPointSprite[bulletList.Count];
                for (int i = 0; i < bulletList.Count; i++)
                    spriteArray[i] = new VertexPointSprite(bulletList[i].position, 50);

                effect.CurrentTechnique = effect.Techniques["PointSprites"];
                Matrix worldMatrix = Matrix.Identity;
                effect.Parameters["xWorld"].SetValue(worldMatrix);
                effect.Parameters["xView"].SetValue(viewMatrix);
                effect.Parameters["xProjection"].SetValue(projectionMatrix);
                effect.Parameters["xTexture"].SetValue(bulletTexture);

                device.RenderState.PointSpriteEnable = true;

                effect.Begin();
                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    device.VertexDeclaration = pointSpriteVertexDeclaration;
                    device.DrawUserPrimitives(PrimitiveType.PointList, spriteArray, 0, spriteArray.Length);
                    pass.End();
                }
                effect.End();

                device.RenderState.PointSpriteEnable = false;
            }
        }

        private void DrawBullets3()
        {
            if (bulletList.Count > 0)
            {

                VertexPositionColor[] SpriteArray = new VertexPositionColor[bulletList.Count];
                for (int i = 0; i < bulletList.Count; i++)
                    SpriteArray[i] = new VertexPositionColor(bulletList[i].position, Color.WhiteSmoke);

                graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;
                graphics.GraphicsDevice.RenderState.PointSize = 64.0f;

                graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
                graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
                graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
                graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;

                graphics.GraphicsDevice.VertexDeclaration
                    = pointSpriteVertexDeclaration;
                Matrix WVPMatrix = Matrix.Identity * viewMatrix * projectionMatrix;
                pointSpritesEffect.Parameters["WVPMatrix"].SetValue(WVPMatrix);

                pointSpritesEffect.Begin();
                foreach (EffectPass pass in pointSpritesEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList,
                       SpriteArray, 0, SpriteArray.Length);

                    pass.End();
                }
                pointSpritesEffect.End();

                graphics.GraphicsDevice.RenderState.PointSpriteEnable = false;
                ////graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
                ////graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;

                ////graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
                ////   //Blend.InverseSourceAlpha;



                graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;
                graphics.GraphicsDevice.RenderState.SourceBlend = Blend.One;
                graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
                graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;

            }
        }

        private void DrawATSTBullets()
        {
            if (ATSTBulletList.Count > 0)
            {

                VertexPositionColor[] SpriteArray = new VertexPositionColor[ATSTBulletList.Count];
                for (int i = 0; i < ATSTBulletList.Count; i++)
                    SpriteArray[i] = new VertexPositionColor(ATSTBulletList[i].position, Color.WhiteSmoke);

                graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;
                graphics.GraphicsDevice.RenderState.PointSize = 64.0f;

                graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
                graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
                graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
                graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;

                graphics.GraphicsDevice.VertexDeclaration
                    = pointSpriteVertexDeclaration;
                Matrix WVPMatrix = Matrix.Identity * viewMatrix * projectionMatrix;
                pointSpritesEffect.Parameters["WVPMatrix"].SetValue(WVPMatrix);

                pointSpritesEffect.Begin();
                foreach (EffectPass pass in pointSpritesEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList,
                       SpriteArray, 0, SpriteArray.Length);

                    pass.End();
                }
                pointSpritesEffect.End();

                graphics.GraphicsDevice.RenderState.PointSpriteEnable = false;
                ////graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
                ////graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;

                ////graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
                ////   //Blend.InverseSourceAlpha;



                graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;
                graphics.GraphicsDevice.RenderState.SourceBlend = Blend.One;
                graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
                graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;

            }
        }


        private void DrawEnemyBullets()
        {
            if (enemyBulletList.Count > 0)
            {

                VertexPositionColor[] SpriteArray = new VertexPositionColor[enemyBulletList.Count];
                for (int i = 0; i < enemyBulletList.Count; i++)
                    SpriteArray[i] = new VertexPositionColor(enemyBulletList[i].position, Color.WhiteSmoke);

                graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;
                graphics.GraphicsDevice.RenderState.PointSize = 64.0f;

                graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
                graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
                graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
                graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;

                graphics.GraphicsDevice.VertexDeclaration
                    = pointSpriteVertexDeclaration;
                Matrix WVPMatrix = Matrix.Identity * viewMatrix * projectionMatrix;
                pointSpritesEffect.Parameters["WVPMatrix"].SetValue(WVPMatrix);

                pointSpritesEffect.Begin();
                foreach (EffectPass pass in pointSpritesEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList,
                       SpriteArray, 0, SpriteArray.Length);

                    pass.End();
                }
                pointSpritesEffect.End();

                graphics.GraphicsDevice.RenderState.PointSpriteEnable = false;
                ////graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
                ////graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;

                ////graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
                ////   //Blend.InverseSourceAlpha;



                graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;
                graphics.GraphicsDevice.RenderState.SourceBlend = Blend.One;
                graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
                graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;

            }
        }


        Effect pointSpritesEffect;


        private void DrawSkybox()
        {
            device.SamplerStates[0].AddressU = TextureAddressMode.Clamp;
            device.SamplerStates[0].AddressV = TextureAddressMode.Clamp;

            device.RenderState.DepthBufferWriteEnable = false;
            Matrix[] skyboxTransforms = new Matrix[skyboxModel.Bones.Count];
            skyboxModel.CopyAbsoluteBoneTransformsTo(skyboxTransforms);
            int i = 0;
            foreach (ModelMesh mesh in skyboxModel.Meshes)
            {
                foreach (Effect currentEffect in mesh.Effects)
                {
                    Matrix worldMatrix = skyboxTransforms[mesh.ParentBone.Index] * Matrix.CreateTranslation(xwingPosition);
                    currentEffect.CurrentTechnique = currentEffect.Techniques["Textured"];
                    currentEffect.Parameters["xWorld"].SetValue(worldMatrix);
                    currentEffect.Parameters["xView"].SetValue(viewMatrix);
                    currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);
                    currentEffect.Parameters["xTexture"].SetValue(skyboxTextures[i++]);
                }
                mesh.Draw();
            }
            device.RenderState.DepthBufferWriteEnable = true;
        }





        /// <summary>
        /// Estimate the Tank's best possible movement speed to it's destination
        /// </summary>
        /// <param name="newDestination">The Tank's target location</param>
        /// <returns>Maximum estimated movement speed for the Tank 
        /// up to Tank.MaxMoveSpeed</returns>
        //public float FindMaxMoveSpeed(Vector2 waypoint)
        //{
        //    float finalSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * (gameSpeed);// * 1.0f);
        //    // Given a velocity v (Tank.MaxMoveSpeed) and an angular velocity 
        //    // w(Tank.MaxAngularVelocity), the smallest turning radius 
        //    // r(turningRadius) ofthe tank is the velocity divided by the turning
        //    // speed: r = v/w 
        //  //  float turningRadius = Tank.MaxMoveSpeed /  Tank.MaxAngularVelocity;
        //    float turningRadius = finalSpeed / (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;


        //    // This code figures out if the tank can move to its waypoint from its 
        //    // current location based on its turning circle(turningRadius) when its 
        //    // moving as fast as possible(Tank.MaxMoveSpeed). For any given turning 
        //    // circle there is an area to either side of the tank that it cannot 
        //    // move into that can be represented by 2 circles of radius turningRadius 
        //    // on either side of the tank. If the waypoint is inside one of these 
        //    // 2 circles the tank will have to slow down before it can move to it

        //    // This creates a vector that’s orthogonal to the tank in the direction 
        //    // it's facing. This means that the vector is at a right angle to the 
        //    // direction the tank is pointing in.

        //    Vector2 orth = new Vector2(enemyPosition.Y, -enemyPosition.Z);

        //    Vector2 XwingPos = new Vector2(xwingPosition.Y, xwingPosition.Z);
        //    Vector2 enemyPos = new Vector2(enemyPosition.Y, enemyPosition.Z);

        //    // In this code we can combine the tanks’ location, the orthogonal 
        //    // vector and the tanks’ turning radius to find the 2 points that 
        //    // describe the centers of the circles the tanks cannot move into. 
        //    // Then we use Vector2.Distance to find the distances from each circle 
        //    // center to the waypoint. Afterwards Math.Min return the distance from 
        //    // the waypoint to whichever circle was closest.
        //    float closestDistance = Math.Min(
        //        Vector2.Distance(XwingPos, enemyPos + (orth * turningRadius)),
        //        Vector2.Distance(XwingPos, enemyPos - (orth * turningRadius)));


        //    // If closestDistance is less than turningRadius, then the waypoint is 
        //    // inside one of the 2 circles the Tank cannot turn into when moving at 
        //    // Tank.MaxMoveSpeed, instead we need to estimate a speed that the tank 
        //    // can move at.
        //    if (closestDistance < turningRadius)
        //    {
        //        // This finds the radius of a circle where the Tank's location and 
        //        // the waypoint are 2 points on opposite sides of the circle.
        //        float radius = Vector2.Distance(enemyPos, XwingPos) / 2;
        //        // Now we use the radius from above to and Tank.MaxAngularVelocity 
        //        // to find out how fast we can move towards the waypoint by taking 
        //        // r = v/w and turning it into v = r*w
        //        finalSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f * radius;
        //    }

        //    return finalSpeed;
        //}

        /// <summary>
        /// Calculates the angle that an object should face, given its position, its
        /// target's position, its current angle, and its maximum turning speed.
        /// </summary>
        public static float TurnToFace(Vector2 position, Vector2 faceThis,
            float currentAngle, float turnSpeed)
        {
            // consider this diagram:
            //         C 
            //        /|
            //      /  |
            //    /    | y
            //  / o    |
            // S--------
            //     x
            // 
            // where S is the position of the spot light, C is the position of the cat,
            // and "o" is the angle that the spot light should be facing in order to 
            // point at the cat. we need to know what o is. using trig, we know that
            //      tan(theta)       = opposite / adjacent
            //      tan(o)           = y / x
            // if we take the arctan of both sides of this equation...
            //      arctan( tan(o) ) = arctan( y / x )
            //      o                = arctan( y / x )
            // so, we can use x and y to find o, our "desiredAngle."
            // x and y are just the differences in position between the two objects.
            float x = faceThis.X - position.X;
            float y = faceThis.Y - position.Y;

            // we'll use the Atan2 function. Atan will calculates the arc tangent of 
            // y / x for us, and has the added benefit that it will use the signs of x
            // and y to determine what cartesian quadrant to put the result in.
            // http://msdn2.microsoft.com/en-us/library/system.math.atan2.aspx
            float desiredAngle = (float)Math.Atan2(y, x);

            // so now we know where we WANT to be facing, and where we ARE facing...
            // if we weren't constrained by turnSpeed, this would be easy: we'd just 
            // return desiredAngle.
            // instead, we have to calculate how much we WANT to turn, and then make
            // sure that's not more than turnSpeed.

            // first, figure out how much we want to turn, using WrapAngle to get our
            // result from -Pi to Pi ( -180 degrees to 180 degrees )
            float difference = WrapAngle(desiredAngle - currentAngle);

            // clamp that between -turnSpeed and turnSpeed.
            difference = MathHelper.Clamp(difference, -turnSpeed, turnSpeed);

            // so, the closest we can get to our target is currentAngle + difference.
            // return that, using WrapAngle again.
            return WrapAngle(currentAngle + difference);
        }

        /// <summary>
        /// Returns the angle expressed in radians between -Pi and Pi.
        /// </summary>
        public static float WrapAngle(float radians)
        {
            while (radians < -MathHelper.Pi)
            {
                radians += MathHelper.TwoPi;
            }
            while (radians > MathHelper.Pi)
            {
                radians -= MathHelper.TwoPi;
            }
            return radians;
        }


    }
}
